package de.danielbasedow.prospecter.server;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import de.danielbasedow.prospecter.core.*;
import de.danielbasedow.prospecter.core.document.Document;
import de.danielbasedow.prospecter.core.document.MalformedDocumentException;
import de.danielbasedow.prospecter.core.schema.Schema;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class HttpApiRequestHandler extends SimpleChannelInboundHandler<Object> {
private static final ObjectMapper mapper = new ObjectMapper();
private final Instance instance;
private FullHttpRequest request;
private static final Logger LOGGER = LoggerFactory.getLogger(HttpApiRequestHandler.class);
public HttpApiRequestHandler(Instance instance) {
this.instance = instance;
}
private final StringBuilder responseBuffer = new StringBuilder();
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof FullHttpRequest) {
this.request = (FullHttpRequest) msg;
} else {
throw new Exception();
}
FullHttpResponse response;
try {
response = dispatch();
} catch (Exception e) {
LOGGER.warn(e.getLocalizedMessage(), e);
response = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.INTERNAL_SERVER_ERROR,
Unpooled.copiedBuffer(e.getLocalizedMessage(), CharsetUtil.UTF_8)
);
}
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
}
protected FullHttpResponse dispatch() throws UndefinedIndexFieldException, MalformedQueryException, MalformedDocumentException, JsonProcessingException {
String uri = request.getUri();
String[] uriParts = uri.split("/");
if (uriParts.length == 0) {
LOGGER.warn("root uri specified, please supply a valid uri! Doing nothing!");
return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR);
}
String schemaName = uriParts[1];
LOGGER.debug("method: " + request.getMethod() + ", schema: '" + schemaName + "'");
if (request.getMethod() == HttpMethod.POST && schemaName != null) {
return matchDocument(instance.getSchema(schemaName));
}
if (request.getMethod() == HttpMethod.PUT && schemaName != null) {
return addQuery(instance.getSchema(schemaName));
}
if (request.getMethod() == HttpMethod.DELETE && schemaName != null) {
String queryId = uriParts[1];
return deleteQuery(instance.getSchema(schemaName), queryId);
}
return null;
}
protected DefaultFullHttpResponse addQuery(Schema schema) throws MalformedQueryException, UndefinedIndexFieldException {
ByteBuf content = request.content();
if (content.isReadable()) {
schema.addQuery(content.toString(CharsetUtil.UTF_8));
}
return new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,
Unpooled.copiedBuffer("", CharsetUtil.UTF_8)
);
}
protected FullHttpResponse matchDocument(Schema schema) throws MalformedDocumentException, JsonProcessingException {
ByteBuf content = request.content();
int matchCount = 0;
ObjectNode node = mapper.getNodeFactory().objectNode();
if (content.isReadable()) {
LOGGER.debug("start matching");
Document doc = schema.getDocumentBuilder().build(content.toString(CharsetUtil.UTF_8));
Matcher matcher = schema.matchDocument(doc);
ArrayNode results = node.putArray("matches");
for (Integer queryId : matcher.getMatchedQueries()) {
matchCount++;
ObjectNode queryNode = results.addObject();
queryNode.put("id", queryId);
}
LOGGER.debug("finished matching");
}
node.put("count", matchCount);
return new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,
Unpooled.copiedBuffer(mapper.writeValueAsString(node), CharsetUtil.UTF_8)
);
}
protected DefaultFullHttpResponse deleteQuery(Schema schema, String queryId) {
if (queryId == null || "".equals(queryId)) {
LOGGER.warn("No query id supplied in DELETE request.");
return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR);
}
Integer qid = Integer.parseInt(queryId, 10);
schema.deleteQuery(qid);
return new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1,
HttpResponseStatus.OK,
Unpooled.copiedBuffer("", CharsetUtil.UTF_8)
);
}
}